package com.googlecode.mvcguice;

import java.lang.reflect.Method;
import java.util.List;

import com.googlecode.mvcguice.routing.ParameterBinder;

public class ControllerAction {
	private final Object instance;
	private final Method method;
	private final List<ParameterBinder> parameterBinders;
	private final String actionPath;

	public ControllerAction(Object instance, Method method, List<ParameterBinder> parameterBinders) {
		this.instance = instance;
		this.method = method;
		this.parameterBinders = parameterBinders;
		this.actionPath = createActionPath(instance, method);
	}

	public Object invoke(RequestContext requestContext) {
		final Object[] args = createArgs(requestContext);
		try {
			return method.invoke(instance, args);
		} catch (Exception e) {
			// TODO: add exception handing
			throw new RuntimeException(e);
		}
	}

	public String getActionPath() {
		return actionPath;
	}

	@Override
	public String toString() {
		return instance.getClass().getName() + "." + method.getName() + parameterBinders;
	}

	private Object[] createArgs(RequestContext requestContext) {
		final int n = parameterBinders.size();
		final Object[] args = new Object[n];
		for (int i = 0; i < n; i++) {
			args[i] = parameterBinders.get(i).bind(requestContext);
		}
		return args;
	}

	//TODO: implement configuration for prefixes
	private String createActionPath(Object instance, Method method) {
		String methodName = camelizedToUnderscored(method.getName());
		return (instance.getClass().getName().replace("controllers", "").replace('.', '/') + '/' + methodName)
				.toLowerCase();
	}

	private String camelizedToUnderscored(String str) {
		final StringBuilder sb = new StringBuilder(str.length() * 2);
		for (int i = 0, n = str.length(); i < n; i++) {
			final char c = str.charAt(i);
			if (Character.isUpperCase(c)) {
				sb.append('_');
				sb.append(Character.toLowerCase(c));
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}
}
